#include "clients-list.h"
#include "../base/log.h"
#include "../base/message-server-client.h"

using std::make_pair;
using std::set;

void ClientsList::add_client(const Message* message) {
    ASSERT(message->type() == messages::LOGIN);

    const messages::Login* login = (const messages::Login*)message;

    ClientInfo* client = new ClientInfo;

    client->set_id(login->id());
    client->set_ip(login->ip());
    client->set_port(login->port());
    client->set_name(login->name());
    client->set_email(login->email());

    clients_.insert(make_pair(login->id(), client));
    ack_segments_.insert(make_pair(login->id(), set<quint32>()));
    // addresses_.insert(make_pair(make_pair(login->ip(), login->port()), client));
}

ClientInfo* ClientsList::search_by_id(ClientId id) {
    std::map<ClientId, ClientInfo*>::iterator it =
        clients_.find(id);

    if (it == clients_.end())
        return NULL;
    return it->second;
}

/*
ClientInfo* ClientsList::search_by_address(quint32 ip, quint16 port) {
    std::map<std::pair<quint32, quint16>, ClientInfo*>::iterator it =
        addresses_.find(make_pair(ip, port));

    if (it == addresses_.end())
        return NULL;
    return it->second;
}
*/

bool ClientsList::add_file_part(const Message* in, Message** out) {
    ASSERT(in->type() == messages::S_LIST_SEGMENT);

    const messages::ListSegment* segment =
        (const messages::ListSegment*)(in);

    ClientInfo* info = search_by_id(in->source());
    if (info == NULL) {
        LOG(WARN) << "Unknown client id = " << in->source();
        return false;
    }

    // vedem daca clientul a trimis deja lista de fisiere
    std::map<ClientId, std::set<quint32> >::iterator it =
        ack_segments_.find(in->source());
    if (it == ack_segments_.end()) {
        LOG(WARN) << "Received extra list parts from " << in->source();
        return false;
    }

    // vedem daca clientul a trimis deja partea asta
    std::set<quint32>::iterator seq = it->second.find(segment->id());
    if (seq == it->second.end()) {
        LOG(WARN) << "Received duplicate list part " << segment->id()
                  << " from " << in->source();
        return false;
    }

    // adaugam lista primita la lista curenta
    FileList* list = info->mutable_filelist();
    for (int i = 0; i < segment->list()->size(); ++i)
        list->push_back(segment->list()->at(i)->clone());

    // memoram ca am primit partea asta
    it->second.insert(segment->id());

    // construim iesirea
    *out = new messages::AckListSegment(segment->id());

    // determinam sfarsitul transmisiunii listei
    bool completed = segment->list()->size() == 0;
    if (completed)
        ack_segments_.erase(in->source());

    return completed;
}

